package com.liuya.safe.user.service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.liuya.common.Util;
import com.liuya.db.DBPower;
import com.liuya.db.MapStorgeColumnAdapter;
import com.liuya.db.MapStorgeObject;
import com.liuya.db.orm.*;
import com.liuya.safe.client.pojo.FieldMetadata;
import com.liuya.safe.client.pojo.TableMetadata;
import com.liuya.safe.client.pojo.UserMetadata;
import com.liuya.safe.model.SafeUser;

public class UserComplexTableAdapter {
    private UserMetadata userMetadata;
    private ComplexTable complexTable;
    private String[] idNames = new String[] { SafeUser.idFieldName };
    private String idColumnName;

    private SingleValueTableAdapter[] singleValueTableAdapters;
    private MultiValueTableAdapter[] multiValueTableAdapters;

    public UserComplexTableAdapter(UserMetadata userMetadata) {
        this.userMetadata = userMetadata;
        adapter();
        FieldMetadata[] fields = userMetadata.getMainTableMetadata().getFields();
        for (int i = 0; i < fields.length; i++) {
            FieldMetadata field = fields[i];
            if (field.getName().equals(SafeUser.idFieldName)) {
                idColumnName = field.getColumnName();
            }
        }

        readySingleValueTableAdapter();
        readyMultiValueTableAdapter();

        readyDeletor();
        readySaver();
        readyUpdator();
        readySelector();
    }

    private void readySingleValueTableAdapter() {
        singleValueTableAdapters = complexTable.getDefaultSingleValueTableAdapters();
    }

    private void readyMultiValueTableAdapter() {
        multiValueTableAdapters = complexTable.getDefaultMultiValueTableAdapters();
    }

    private void readySelector() {
//        selector = new ComplexTableSelectorImpl();
//        selector.setComplexTable(complexTable);
//        selector.setMainTableObjectNewer(new MapStorageObjectNewer());
//        selector.setSingleValueAdapters(singleValueTableAdapters);
//        selector.setMultiValueAdapters(multiValueTableAdapters);
    }

    private void readyUpdator() {
//        updator = new ComplexTableUpdatorImpl();
//        updator.setComplexTable(complexTable);
//        updator.setSingleValueAdapters(singleValueTableAdapters);
//        updator.setMultiValueAdapters(multiValueTableAdapters);
    }

    private void readySaver() {
//        saver = new ComplexTableSaverImpl();
//        saver.setComplexTable(complexTable);
//        saver.setSingleValueAdapters(singleValueTableAdapters);
//        saver.setMultiValueAdapters(multiValueTableAdapters);
    }

    private void readyDeletor() {
//        deletor = new ComplexTableDeletorImpl();
//        deletor.setComplexTable(complexTable);
    }

    public ComplexTable getComplexTable() {
        return complexTable;
    }

    public SafeUser toUser(MapStorgeObject mso) {
        if (mso == null)
            return null;

        SafeUser user = new SafeUser();
        readFromMainTable(mso, user);
        readFromSingleValueTables(mso, user);
        readFromMultiValueTables(mso, user);

        return user;
    }

    private void readFromMultiValueTables(MapStorgeObject mso, SafeUser user) {
        TableMetadata[] tableMds = userMetadata.getMultiValueTableMetadatas();
        if (Util.isEmpty(tableMds))
            return;

        Table[] tables = complexTable.getMultiValueTables();
        for (int tableIndex = 0; tableIndex < tableMds.length; tableIndex++) {
            TableMetadata tableMd = tableMds[tableIndex];
            FieldMetadata[] fields = tableMd.getFields();
            String mapKey = tables[tableIndex].getId() + "";

            List tableMsos = (List) mso.get(mapKey);
            if (tableMsos != null) {
                for (int fieldIndex = 0; fieldIndex < fields.length; fieldIndex++) {
                    FieldMetadata field = fields[fieldIndex];
                    String columnName = field.getColumnName();
                    String name = field.getName();

                    if (!name.equals(SafeUser.idFieldName)) {
                        List values = new ArrayList(tableMsos.size());
                        for (Iterator iter = tableMsos.iterator(); iter.hasNext();) {
                            MapStorgeObject tableMso = (MapStorgeObject) iter.next();
                            Object value = tableMso.get(columnName);
                            values.add(value);
                        }

                        user.set(name, values);
                    }// end of if
                }// end of fields for loop
            }// end of tableMsos if
        }
    }

    private void readFromSingleValueTables(MapStorgeObject mso, SafeUser user) {
        TableMetadata[] tableMds = userMetadata.getSingleValueTableMetadatas();
        if (Util.isEmpty(tableMds))
            return;

        Table[] tables = complexTable.getSingleValueTables();
        for (int tableIndex = 0; tableIndex < tableMds.length; tableIndex++) {
            TableMetadata tableMd = tableMds[tableIndex];
            FieldMetadata[] fields = tableMd.getFields();
            String mapKey = tables[tableIndex].getId() + "";

            MapStorgeObject tableMso = (MapStorgeObject) mso.get(mapKey);
            if (tableMso != null) {
                for (int fieldIndex = 0; fieldIndex < fields.length; fieldIndex++) {
                    FieldMetadata field = fields[fieldIndex];
                    String columnName = field.getColumnName();
                    Object value = tableMso.get(columnName);

                    String name = field.getName();
                    if (!name.equals(SafeUser.idFieldName))
                        user.set(name, value);
                }
            }
        }
    }

    private void readFromMainTable(MapStorgeObject mso, SafeUser user) {
        TableMetadata mainTableMetadata = userMetadata.getMainTableMetadata();
        FieldMetadata[] fields = mainTableMetadata.getFields();
        for (int i = 0; i < fields.length; i++) {
            String columnName = fields[i].getColumnName();
            Object value = mso.get(columnName);

            String name = fields[i].getName();
            user.set(name, value);
        }
    }

    public MapStorgeObject toMSO(SafeUser user) {
        if (user == null) {
            return null;
        }

        MapStorgeObject mso = new MapStorgeObject();

        setMainTableValues(user, mso);
        setSingleValueTableValues(user, mso);
        setMultiValueTableValues(user, mso);

        return mso;
    }

    private void setMultiValueTableValues(SafeUser user, MapStorgeObject mso) {
        TableMetadata[] tableMds = userMetadata.getMultiValueTableMetadatas();
        if (Util.isEmpty(tableMds)) {
            return;
        }

        Table[] tables = complexTable.getMultiValueTables();
        for (int tableIndex = 0; tableIndex < tableMds.length; tableIndex++) {
            TableMetadata tableMd = tableMds[tableIndex];
            FieldMetadata[] fields = tableMd.getFields();
            String mapKey = tables[tableIndex].getId() + "";

            Object idValue = mso.get(SafeUser.idFieldName);
            List[] values = new List[fields.length - 1];
            Iterator[] iters = new Iterator[values.length];
            String[] columnNames = new String[values.length];
            String idColumnName = "";

            int index = 0;
            int maxSize = 0;
            for (int fieldIndex = 0; fieldIndex < fields.length; fieldIndex++) {
                FieldMetadata field = fields[fieldIndex];
                String columnName = field.getColumnName();
                String name = field.getName();

                if (name.equals(SafeUser.idFieldName)) {
                    idColumnName = columnName;
                } else {
                    List fieldValues = (List) user.get(name);
                    if (fieldValues == null) {
                        fieldValues = new ArrayList(0);
                    }

                    values[index] = fieldValues;
                    iters[index] = fieldValues.iterator();
                    columnNames[index] = columnName;
                    index++;

                    int size = fieldValues.size();
                    if (size > maxSize) {
                        maxSize = size;
                    }
                }
            }

            if (maxSize > 0) {
                List tableMsos = new ArrayList(maxSize);
                mso.put(mapKey, tableMsos);

                for (int msoIndex = 0; msoIndex < maxSize; msoIndex++) {
                    MapStorgeObject tableMso = new MapStorgeObject();
                    tableMsos.add(tableMso);

                    tableMso.put(idColumnName, idValue);
                    for (int iterIndex = 0; iterIndex < iters.length; iterIndex++) {
                        Iterator iter = iters[iterIndex];
                        if (iter.hasNext()) {
                            tableMso.put(columnNames[iterIndex], iter.next());
                        }
                    }
                }
            }
        }
    }

    private void setSingleValueTableValues(SafeUser user, MapStorgeObject mso) {
        TableMetadata[] tableMds = userMetadata.getSingleValueTableMetadatas();
        if (Util.isEmpty(tableMds)) {
            return;
        }

        Table[] tables = complexTable.getSingleValueTables();
        for (int i = 0; i < tableMds.length; i++) {
            TableMetadata tableMd = tableMds[i];
            FieldMetadata[] fields = tableMd.getFields();
            String mapKey = tables[i].getId() + "";

            Object idValue = mso.get(SafeUser.idFieldName);
            String idColumnName = "";

            boolean noValue = true;
            MapStorgeObject tableMso = new MapStorgeObject();

            for (int j = 0; j < fields.length; j++) {
                FieldMetadata field = fields[j];
                String columnName = field.getColumnName();
                String name = field.getName();

                if (name.equals(SafeUser.idFieldName)) {
                    idColumnName = columnName;
                } else {
                    Object value = user.get(name);
                    tableMso.put(columnName, value);

                    if (noValue && value != null) {
                        noValue = false;
                    }
                }
            }

            if (!noValue) {
                tableMso.put(idColumnName, idValue);
                mso.put(mapKey, tableMso);
            }
        }
    }

    private void setMainTableValues(SafeUser user, MapStorgeObject mso) {
        TableMetadata table = userMetadata.getMainTableMetadata();
        FieldMetadata[] fields = table.getFields();
        for (int i = 0; i < fields.length; i++) {
            FieldMetadata field = fields[i];
            String columnName = field.getColumnName();
            String name = field.getName();

            Object value = user.get(name);
            mso.put(columnName, value);
        }
    }

    private ComplexTable adapter() {
        complexTable = new ComplexTable();

        TableMetadata mainTableMetadata = userMetadata.getMainTableMetadata();
        Table mainTable = adapter(mainTableMetadata, false);
        complexTable.setMainTable(mainTable);
        // complexTable.setIdColumns( mainTable.getIdColumns() );

        TableMetadata[] singleValueTableMetadatas = userMetadata.getSingleValueTableMetadatas();
        complexTable.setSingleValueTables(adapter(singleValueTableMetadatas, false));

        TableMetadata[] multiValueTableMetadatas = userMetadata.getMultiValueTableMetadatas();
        complexTable.setMultiValueTables(adapter(multiValueTableMetadatas, true));

        return complexTable;
    }

    private Table[] adapter(TableMetadata[] tablesMetadatas, boolean isMulti) {
        if (Util.isEmpty(tablesMetadatas))
            return null;

        Table[] tables = new Table[tablesMetadatas.length];
        for (int i = 0; i < tables.length; i++) {
            tables[i] = adapter(tablesMetadatas[i], isMulti);
        }

        return tables;
    }

    public Table adapter(TableMetadata table, boolean isMulti) {
        FieldMetadata[] fields = table.getFields();
        FieldMetadata[] uniqueFields = table.getUniqueFields();

        TableNewer tn = new TableNewer();
        String[] names = getColumnNames(fields);
        tn.setColumnNames(names);
        tn.setId(DBPower.getTableId(table.getDatasourceName(), table.getSqlTableName()));
        String idColumnName = null;
        for (int i = 0; i < fields.length; i++) {
            FieldMetadata metadata = fields[i];
            if (metadata.getName().equals(SafeUser.idFieldName)) {
                idColumnName = metadata.getColumnName();
                break;
            }
        }

        if (!isMulti) {
            tn.setIdColumnNames(new String[] { idColumnName });
        }
        tn.setTableName(table.getSqlTableName());
        tn.setUniqueColumnNames(getColumnNames(uniqueFields));

        for (int i = 0; i < fields.length; i++) {
            String name = fields[i].getColumnName();
            tn.put(name, new MapStorgeColumnAdapter(name, fields[i].getJavaType()));
        }

        Table table2 = tn.getTable();
        table2.setDatasourceName(table.getDatasourceName());
        return table2;
    }

    private String[] getColumnNames(FieldMetadata[] fields) {
        if (fields == null || Util.isEmpty(fields))
            return null;

        String[] names = new String[fields.length];
        for (int i = 0; i < names.length; i++) {
            names[i] = fields[i].getColumnName();
        }

        return names;
    }

    public SafeUser javabeanToUser(MapStorgeObject mso) {
        if (mso == null)
            return null;

        SafeUser user = new SafeUser();
        user.setId((String)mso.get(SafeUser.idFieldName));
        FieldMetadata[] fields = userMetadata.getMainTableMetadata().getFields();
        for (int i = 0; i < fields.length; i++) {
            String name = fields[i].getName();
            user.set(name, mso.get(name));
        }

        return user;
    }
}
